﻿//-------------------------------------------------------------------
//	Copyright (c) 2013-2014  Zhirnov Andrey
//	This file is part of the "UX OpwnGL Framework" project.
//	See copyright notice in "UX_GL_Framework.h".
//-------------------------------------------------------------------

#include "CApplication.h"
#include "Loaders/ShaderLoader.h"


void __log_write (const char *msg, int level, const char *file, int line)
{
	UX_STL::UXLogger::LOGGER()->WriteExt( msg, (UX_STL::e_log_msg::type)level, file, line );
}

namespace Framework
{

/*
=================================================
	constructor
=================================================
*/
	CApplication::CApplication () :
		_lastTime(0.0f), _timeDelta(0.0f), _updateTime(0.0f),
		_mainThread(&_window)
	{
	}
	
/*
=================================================
	destructor
=================================================
*/
	CApplication::~CApplication ()
	{
	}
	
/*
=================================================
	OnUpdate
=================================================
*/
	void CApplication::OnUpdate (CWindow *pWnd)
	{
		const float	last_time = _lastTime;

		_lastTime		= (float)_timer.GetTime();
		_timeDelta		= _lastTime - last_time;
		_updateTime   += _timeDelta;

		if ( _updateTime > 1.0f/60.0f )
		{
			Input()->Update();
			Update();
			Input()->Reset();

			_updateTime = 0.0f;
		}

		Draw();
		Window()->SwapBuffers();
	}
	
/*
=================================================
	ProcessMessage
=================================================
*/
	void CApplication::ProcessMessage (const TWindowEvent & wndEvent)
	{
		if ( wndEvent.eEventType == e_wnd_event::MESSAGE )
		{
			if ( wndEvent.sEvent.sMsg.eMsg == TWindowEvent::TMessage::RESIZE or
				 wndEvent.sEvent.sMsg.eMsg == TWindowEvent::TMessage::MAXIMIZED )
			{
				OnResize();
			}
		}
	}
	
/*
=================================================
	_Init
=================================================
*/
	void CApplication::_Init ()
	{
		const float	s_vertices[] = {
			-1.0f,  1.0f,
			-1.0f, -1.0f,
			 1.0f,  1.0f,
			 1.0f, -1.0f
		};

		_quadVertices.Create( gl_buffer::VERTEX );
		_quadVertices.SetData( s_vertices, sizeof(s_vertices), gl_usage::STATIC );

		GLVerticesAttribs_t	a_attribs;
		a_attribs.PushBack( GLVertexAttrib( 0, 2, 0, 0, gl_vertex::FLOAT, false ) );
		
		_quadVertexAttribs.Create( a_attribs, _quadVertices.Id(), 0, 4, 0, gl_primitive::TRIANGLE_STRIP );
	}
	
/*
=================================================
	_Free
=================================================
*/
	void CApplication::_Free ()
	{
		_quadVertexAttribs.Destroy();
		_quadVertices.Destroy();
		
		OnFree();

		ShaderLoader::FreeCache();
	}

/*
=================================================
	DrawPoint
=================================================
*/
	void CApplication::DrawPoint ()
	{
		_quadVertexAttribs.Bind();
		SMAN()->DrawArrays( gl_primitive::POINT, 0, 1 );
	}
	
/*
=================================================
	DrawQuad
=================================================
*/
	void CApplication::DrawQuad ()
	{
		_quadVertexAttribs.Bind();
		SMAN()->DrawArrays( gl_primitive::TRIANGLE_STRIP, 0, 4 );
	}

/*
=================================================
	_RunDefault
=================================================
*/
	bool CApplication::_RunDefault ()
	{
		CWindow::TDescriptor	desc;
		GLWindow::TGLDescriptor	gl_desc;

		desc.vSize			= uvec2( 640, 480 );
		desc.vPos			= ivec2( 0, 0 );
		desc.eStyle			= e_wnd_style::DEF_WINDOWED;
		desc.uFreq			= 0;
		desc.bFullScreen	= false;

		gl_desc.eFlags			= e_glinit_flags::DEFAULT_CORE;
		gl_desc.hSharedRC		= null;
		gl_desc.uColorBits		= 32;
		gl_desc.uDepthBits		= 24;
		gl_desc.uStencilBits	= 8;
		gl_desc.uMSAASamples	= 16;
		gl_desc.uColorSamples	= 8;
		gl_desc.bVSync			= true;

		return _Run( "demo", desc, gl_desc );
	}

/*
=================================================
	_Run
=================================================
*/
	bool CApplication::_Run (uni_c_string resPath, const CWindow::TDescriptor &desc, const GLWindow::TGLDescriptor &glDesc, EInitFlags::type flags)
	{
		GLWindow	&	wnd = this->_window;
		
		bool	b_found = FileSystem::FindAndSetCurrentDir( resPath, 6 );
		ASSERT( b_found and "can't find resource directory" );

		_logger.Create(	e_log_output::MESSAGE_BIT
						 |	e_log_output::LOG_FILE_BIT
						 , "../log.html" );
		
		TPlatform::GetSystemInfo( _systemInfo );

		CHECK_RETURN( wnd.CreateGL( GLWindow::TDescriptorExt( desc, glDesc, true ), "Demo",
									TWindowClass("DemoApplication", e_wc_style::GRAY) ) );
		wnd.AddUpdater( this );
		wnd.AddEventListener( this, e_wnd_event::MESSAGE );

		_input.Init( &wnd );

		wnd.MakeCurrent();
		CHECK_RETURN( this->_render.Init( &wnd ) );

		if ( EnumCmp( flags, EInitFlags::USE_OPENCL ) )
		{
			this->_clDevice = new CLDevice();
			CHECK_RETURN( this->_clDevice->Init( "", cl_device::GPU, wnd.Handles().hRC, wnd.Handles().hDC ) );
		}

		string	str;
		this->_render.GetOpenGLInfo( str );
		this->_render.GetOpenGLParams( str );

		if ( this->_clDevice.IsNotNull() )
		{
			this->_clDevice->GetOpenCLInfo( str );
			this->_clDevice->GetOpenCLParams( str );
		}
		LOG( str.cstr(), e_log_msg::INFO );

		this->_Init();
		this->OnInit();
		
		_lastTime = (float)_timer.GetTime();
			
		wnd.Show();
		wnd.Loop();
	
		wnd.MakeCurrent();
		this->_Free();

		if ( this->_clDevice.IsNotNull() )
		{
			this->_clDevice->Destroy();
			this->_clDevice = null;
		}
		this->_render.Destroy();
		wnd.Destroy();

		return true;
	}
	
//-------------------------------------------------------------------

}	// Framework


#include <stl_core/ux_stl_core_lib.h>
#include <stl_ext/ux_stl_ext_lib.h>

